import { _decorator, Component, Node, Prefab, instantiate, math, BoxCollider, Label, Animation, AudioClip, AudioSource, sys } from 'cc'
import { Bullet } from '../bullet/Bullet'
import { BulletProp } from '../bullet/BulletProp'
import { boss } from '../plane/boss'
import { EnemyPlane } from '../plane/EnemyPlane'
import { sound } from '../sound'
import { Constant } from './Constant'
const { ccclass, property } = _decorator

@ccclass('GameManager')
export class GameManager extends Component {
  @property(Node)
  myPlane: Node = null // 玩家飞机节点
  @property(Node)
  bulletManager: Node = null // 子弹管理节点

  // 子弹预制
  @property(Prefab)
  bullet01: Prefab = null
  @property(Prefab)
  bullet02: Prefab = null
  @property(Prefab)
  bullet03: Prefab = null
  @property(Prefab)
  bullet04: Prefab = null
  @property(Prefab)
  bullet05: Prefab = null

  // 大招预制
  @property(Prefab)
  skill: Prefab = null

  // 敌机预制
  @property(Prefab)
  enemyPlane01: Prefab = null
  @property(Prefab)
  enemyPlane02: Prefab = null

  // 道具预制
  @property(Prefab)
  prop01: Prefab = null
  @property(Prefab)
  prop02: Prefab = null
  @property(Prefab)
  prop03: Prefab = null
  @property(Prefab)
  enemyExplode: Node = null // 敌人爆炸效果

  // boss预制
  @property(Prefab)
  boss: Prefab = null // boss预制

  bossWarfare = false // 是否是boss战

  // 场景节点
  @property(Node)
  gameIndexNode: Node = null // 0主界面节点
  @property(Node)
  gameStartNode: Node = null // 1游戏中界面
  @property(Node)
  gameOverNode: Node = null // 2游戏结束界面
  @property(Node)
  myExplodeNode: Node = null // 玩家爆炸效果
  @property(Node)
  bloodNode: Node = null // 玩家血量节点
  @property(Label)
  scoreText: Label = null // 本局得分
  @property(Label)
  maxScoreText: Label = null // 最高得分
  @property(Animation)
  gameOverAnimation: Animation = null // 结束动画

  // 音频
  @property(Node)
  sound: Node = null

  soundScript = null // 音频脚本

  bulletSpeed = 1.5 // 玩家默认子弹移动速度
  emitSpace = 0.3 // 玩家默认子弹发射间隔
  bulletType = 1 // 玩家默认子弹类型
  hurt = 1 // 子弹伤害

  whetherEmit = false // 玩家子弹是否发射
  timeRecord = 0 // 玩家子弹时间记录

  score = 0 // 玩家积分
  propScore = 50 // 获取道具积分
  maxScore = '0' // 历史最高分

  initBloodVolume = 10 // 玩家初始血量
  bloodVolume = 10 // 玩家当前血量

  // 敌人飞机生成数据
  enemyData = {
    difficulty: 1, // 敌人生成难度 1-3
    space: 1, // 生成敌机间隔 s
    timeRecord: 0, // 生成敌机时间记录
  }

  start() {
    // 读取历史最高分
    const maxScore = sys.localStorage.getItem('maxScore')
    if (maxScore) this.maxScore = maxScore

    this.soundScript = this.sound.getComponent(sound) // 获取音频脚本
    this.gameInit() // 初始化
  }

  update(deltaTime: number) {
    // 游戏状态判断 1游戏中
    if (Constant.gameState === 1) {
      this.myEmitBullet(deltaTime) // 玩家发射子弹
      if (!this.bossWarfare) this.creatEnemy(deltaTime) // 创建敌机
    }
  }

  // 初始化游戏
  gameInit() {
    Constant.gameState = 0
    this.soundScript.soundPlay('button')
    this.gameIndexNode.active = true
    this.gameStartNode.active = false
    this.gameOverNode.active = false
    this.myPlane.setPosition(0, 0, 35) // 玩家飞机回到原位
  }

  // 开始游戏
  gameStart() {
    console.log('🚀 - 开始游戏')
    this.soundScript.soundPlay('button')
    Constant.gameState = 1
    /* 
      数据恢复默认值
    */
    this.bulletSpeed = 1.5 // 玩家默认子弹移动速度
    this.emitSpace = 0.3 // 玩家默认子弹发射间隔
    this.bulletType = 1 // 玩家默认子弹类型
    this.whetherEmit = false // 玩家子弹是否发射
    this.timeRecord = 0 // 玩家子弹时间记录
    this.bossWarfare = false // 是否是boss战
    this.propScore = 50 // 获取道具积分
    this.score = 0 // 玩家积分
    this.hurt = 1 // 子弹伤害
    this.bloodVolume = this.initBloodVolume // 玩家血量
    this.enemyData = {
      difficulty: 1, // 敌人生成难度 1-3
      space: 1, // 生成敌机间隔 s
      timeRecord: 0, // 生成敌机时间记录
    }
    this.scoreText.string = '0'
    this.myExplodeNode.active = false // 隐藏死亡效果
    this.gameIndexNode.active = false
    this.gameStartNode.active = true
    this.gameOverNode.active = false
    this.myPlane.setPosition(0, 0, 35) // 玩家飞机回到原位
    this.schedule(this.improveDifficulty, 10, 1) // 提升难度
  }

  // 结束游戏
  gameOver() {
    console.log('🚀 - 结束游戏')
    Constant.gameState = 2

    // 获取历史最高分
    if (this.score > +this.maxScore) {
      this.maxScore = this.score.toString()
      sys.localStorage.setItem('maxScore', this.maxScore)
    }
    this.maxScoreText.string = this.maxScore // 渲染历史最高分
    this.myPlane.getComponent(AudioSource).play() // 播放死亡音效
    this.myExplodeNode.active = true // 播放死亡效果

    this.scheduleOnce(() => {
      this.bloodNode.active = false // 隐藏血条
      this.gameIndexNode.active = false
      this.gameStartNode.active = false
      this.gameOverNode.active = true
      this.gameOverAnimation.play() // 播放结束动画
      this.unschedule(this.improveDifficulty) // 销毁提升难度定时器
      this.destroyEnemy()
    }, 1)
  }

  // 销毁子弹和敌机
  destroyEnemy() {
    this.node.removeAllChildren() // 销毁敌机
    this.bulletManager.removeAllChildren() // 销毁子弹
  }

  // 创建道具
  createdProp() {
    let type = math.randomRangeInt(1, 4)
    const propNode = instantiate(this['prop0' + type])
    let randomX = math.randomRangeInt(-20, 20) // 生成随机位置X
    let pos = [randomX, 0, -60]
    propNode.setPosition(...pos)
    const propComp = propNode.getComponent(BulletProp)
    propComp.set(this) // 设置道具信息
    propNode.setParent(this.node) // 追加到父节点
  }

  // 提升难度
  improveDifficulty() {
    this.enemyData.difficulty++
    if (this.enemyData.difficulty == 2) {
      this.enemyData.space = 0.8
    } else if (this.enemyData.difficulty == 3) {
      this.enemyData.space = 0.5
    }
    console.log('🚀 - 难度升级', this.enemyData.difficulty)
  }

  // 玩家发射子弹
  myEmitBullet(deltaTime: number) {
    this.timeRecord += deltaTime
    if (this.whetherEmit && this.timeRecord > this.emitSpace) {
      this.timeRecord = 0
      let bulletDataArr = null
      // 判断子弹类型
      switch (this.bulletType) {
        // H子弹
        case 2:
          this.hurt = 3
          bulletDataArr = this.createBulletDataH(this.myPlane, 3)
          this.soundScript.soundPlay('bullet2')
          break
        // S子弹
        case 3:
          this.hurt = 2
          bulletDataArr = this.createBulletDataS(this.myPlane)
          this.soundScript.soundPlay('bullet1')
          break
        // M子弹
        default:
          this.hurt = 5
          bulletDataArr = this.createBulletDataM(this.myPlane)
          this.soundScript.soundPlay('bullet1')
          break
      }
      this.creatBullet(bulletDataArr)
    }
  }

  // 敌机发射子弹
  enemyEmitBullet(node: Node) {
    let num = math.randomRangeInt(0, 5) // 生成随机数字
    let bulletDataArr = null
    if (num < this.enemyData.difficulty) {
      bulletDataArr = this.createBulletDataS(node, 1, 4, 2)
    } else {
      bulletDataArr = this.createBulletDataM(node, 1, 4, 2)
    }
    this.creatBullet(bulletDataArr, true)
  }

  // Boss发射子弹
  bossEmitBullet(node: Node, difficulty) {
    if (difficulty === 1) {
      this.creatBullet(this.createBulletDataM(node, 0.6, 4, 20, 0), true)
    } else {
      this.creatBullet(this.createBulletDataS(node, 0.6, 4, 20, 0), true)
    }
    this.scheduleOnce(() => {
      this.creatBullet(this.createBulletDataH(node, 1.5, 2, 15, 6.7), true)
    }, 0.2)
    this.scheduleOnce(() => {
      if (difficulty === 3) {
        this.creatBullet(this.createBulletDataS(node, 0.8, 4, 15.8, 14.1), true)
        this.creatBullet(this.createBulletDataS(node, 0.8, 4, 15.8, -14.1), true)
      } else {
        this.creatBullet(this.createBulletDataM(node, 0.8, 4, 15.8, 14.1), true)
        this.creatBullet(this.createBulletDataM(node, 0.8, 4, 15.8, -14.1), true)
      }
    }, 0.4)
  }

  // 创建S子弹信息 扇形三发子弹
  createBulletDataS(node: Node, bulletSpeed: number = this.bulletSpeed, bulletType: number = this.bulletType, offsetZ: number = -2, offsetX: number = 0) {
    let pos = node.position
    return [
      {
        pos: {
          x: pos.x + offsetX - 2,
          y: pos.y,
          z: pos.z + offsetZ,
        },
        offsetX: -0.2, // 子弹X轴偏移量
        bulletSpeed, // 子弹速度
        bulletType, // 子弹类型
      },
      {
        pos: {
          x: pos.x + offsetX,
          y: pos.y,
          z: pos.z + offsetZ,
        },
        offsetX: 0, // 子弹X轴偏移量
        bulletSpeed, // 子弹速度
        bulletType, // 子弹类型
      },
      {
        pos: {
          x: pos.x + offsetX + 2,
          y: pos.y,
          z: pos.z + offsetZ,
        },
        offsetX: +0.2, // 子弹X轴偏移量
        bulletSpeed, // 子弹速度
        bulletType, // 子弹类型
      },
    ]
  }

  // 创建H子弹信息 两发激光子弹
  createBulletDataH(node: Node, bulletSpeed: number = this.bulletSpeed, bulletType: number = this.bulletType, offsetZ: number = -2, offsetX: number = 3.4) {
    let pos = node.position
    return [
      {
        pos: {
          x: pos.x - offsetX,
          y: pos.y,
          z: pos.z + offsetZ,
        },
        offsetX: 0, // 子弹X轴偏移量
        bulletSpeed, // 子弹速度
        bulletType, // 子弹类型
      },
      {
        pos: {
          x: pos.x + offsetX,
          y: pos.y,
          z: pos.z + offsetZ,
        },
        offsetX: 0, // 子弹X轴偏移量
        bulletSpeed, // 子弹速度
        bulletType, // 子弹类型
      },
    ]
  }

  // 创建M子弹信息 一发大型子弹
  createBulletDataM(node: Node, bulletSpeed: number = this.bulletSpeed, bulletType: number = this.bulletType, offsetZ: number = -2, offsetX: number = 0) {
    let pos = node.position
    return [
      {
        pos: {
          x: pos.x + offsetX,
          y: pos.y,
          z: pos.z + offsetZ,
        },
        offsetX: 0, // 子弹X轴偏移量
        bulletSpeed, // 子弹速度
        bulletType, // 子弹类型
      },
    ]
  }

  // 创建子弹
  // 参数1 子弹参数对象组成的数组 包含 位置 偏移量 速度 类型
  // 参数2 是否是敌机
  creatBullet(bulletDataArr, isEnemy = false) {
    for (let index = 0; index < bulletDataArr.length; index++) {
      let { pos, offsetX, bulletSpeed, bulletType } = bulletDataArr[index]
      let bullet = 'bullet0' + bulletType
      const bulletNode = instantiate(this[bullet]) // 创建子弹
      bulletNode.setPosition(pos.x, pos.y, pos.z) // 设置子弹生成位置

      // 设置子弹移动速度
      const bulletComp = bulletNode.getComponent(Bullet)
      bulletComp.set(bulletSpeed, offsetX, this.hurt, isEnemy)
      bulletNode.setParent(this.bulletManager) // 挂载子弹到管理面板

      // 地方子弹更改判定 要在挂载组件后调用
      if (isEnemy) {
        const colliderCom = bulletNode.getComponent(BoxCollider)
        colliderCom.setGroup(Constant.collisionGroup.ENEMY_PLANE) // 设置分类
        colliderCom.setMask(Constant.collisionGroup.MY_PLANE) // 设置触发点
      }
    }
  }

  // 创建boss
  creatBoss() {
    const bossNode = instantiate(this.boss)
    bossNode.setPosition(0, 0, -80)
    const bossComp = bossNode.getComponent(boss)
    bossComp.set(this)
    bossNode.setParent(this.node)
    this.bossWarfare = true
  }

  // 创建敌机
  creatEnemy(deltaTime: number) {
    this.enemyData.timeRecord += deltaTime
    if (this.enemyData.timeRecord > this.enemyData.space) {
      let enemyType = Constant.enemyType[math.randomRangeInt(0, 2)] // 敌机类型数据
      let randomRangeInt = math.randomRangeInt(0, 6) // 敌机类型随机数判断
      switch (this.enemyData.difficulty) {
        // 难度1
        case 1:
          this.enemyCombination1(enemyType) // 敌机组合1
          break
        // 难度2
        case 2:
          if (randomRangeInt === 5) {
            this.enemyCombination2(enemyType) // 敌机组合2
          } else {
            this.enemyCombination1(enemyType) // 敌机组合1
          }
          break
        // 难度3
        case 3:
          if (randomRangeInt === 4) {
            this.enemyCombination2(enemyType) // 敌机组合2
          } else if (randomRangeInt === 5) {
            this.enemyCombination3(enemyType) // 敌机组合3
          } else {
            this.enemyCombination1(enemyType) // 敌机组合1
          }
          break
        default:
          break
      }
      this.enemyData.timeRecord = 0 // 重制时间
    }
  }
  // 敌机组合1 会发射子弹的单个敌人
  enemyCombination1(enemyType) {
    let randomX = math.randomRangeInt(-25, 25) // 生成随机位置X
    let posArr = [[randomX, 0, -70]]
    this.createdEnemyCombination(posArr, enemyType) // 创建组合敌机
  }
  // 敌机组合2 一字五架飞机 不会发射子弹
  enemyCombination2(enemyType) {
    let posArr: any = [
      [-20, 0, -70],
      [-10, 0, -70],
      [0, 0, -70],
      [10, 0, -70],
      [20, 0, -70],
    ]
    this.createdEnemyCombination(posArr, enemyType) // 创建组合敌机
  }
  // 敌机组合3 人字七架飞机 不会发射子弹
  enemyCombination3(enemyType) {
    let posArr: any = [
      [-21, 0, -80],
      [-14, 0, -75],
      [-7, 0, -70],
      [0, 0, -65],
      [7, 0, -70],
      [14, 0, -75],
      [21, 0, -80],
    ]
    this.createdEnemyCombination(posArr, enemyType) // 创建组合敌机
  }

  // 创建组合敌机
  // 参数1 位置数组
  // 参数2 敌机信息参数
  createdEnemyCombination(posArr, enemyType) {
    // 生成随机敌机类型
    for (let index = 0; index < posArr.length; index++) {
      // 生成随机敌机类型
      let enemy = `enemyPlane0${enemyType.type}`
      const enemyNode = instantiate(this[enemy]) // 创建敌机
      enemyNode.setPosition(...posArr[index]) // 设置敌机生成位置
      const enemyComp = enemyNode.getComponent(EnemyPlane)
      // 设置敌机信息
      enemyComp.set(this, this.enemyExplode, enemyType.moveSpeed, posArr.length === 1, this.enemyData.difficulty)
      enemyNode.setParent(this.node) // 追加到父节点
    }
  }

  // 创建大招
  createdSkill() {
    let posArr: [number, number, number][] = [
      [0, 0, 90],
      // [-25, 0, 110],
      // [25, 0, 110],
    ]
    // 生成随机敌机类型
    for (let index = 0; index < posArr.length; index++) {
      const skillNode = instantiate(this.skill)
      const skillComp = skillNode.getComponent(Bullet)
      skillComp.set(this.bulletSpeed, 0, 30)
      skillNode.setPosition(...posArr[index])
      skillNode.setParent(this.node) // 追加到父节点
    }
  }
  // 开启护盾
  openShield() {
    let hdNode = this.myPlane.getChildByName('hd')
    let s = 4 // 持续时长
    hdNode.active = true
    this.scheduleOnce(() => {
      hdNode.getComponent(Animation).play()
    }, s - 1)
    this.scheduleOnce(() => {
      hdNode.active = false
    }, s)
  }

  // 玩家切换发射状态
  switchEmit(boo: boolean) {
    this.whetherEmit = boo
  }

  // 设置玩家子弹类型和伤害
  setBulletData(bulletType: number) {
    this.bulletType = bulletType
  }

  // 增加积分
  addScore(number: number) {
    // boss死亡
    if (number === 500) {
      this.bossWarfare = false
      this.myPlane.getComponent(AudioSource).play() // 播放死亡音效
    }
    this.score += number
    this.soundScript.soundPlay('enemy')
    this.scoreText.string = this.score.toString()
    if (this.score > this.propScore) {
      this.propScore += 100 * this.enemyData.difficulty
      this.createdProp() // 创建道具
    }
    // 产生boss
    if (this.score % 1000 === 0) {
      this.creatBoss()
    }
  }

  // 飞机被击中
  bloodReduction() {
    this.bloodVolume--
    if (this.bloodVolume < 0) return
    this.bloodNode.active = true // 显示血条
    // 设置血条长度
    this.bloodNode.getChildByName('face').setScale(this.bloodVolume * (12 / this.initBloodVolume), 1, 1)
    if (this.bloodVolume === 0) {
      this.gameOver()
    }
  }
}
